﻿using System.Collections.Generic;
using UnityEngine;
using static CGF.ScrollView;

namespace CGF
{
    public class ScrollViewDirHorizontal : ScrollViewDirBase
    {
        public ScrollViewDirHorizontal(ScrollView main) : base(main) { }

        public override void UpdateCellsPos(float x, float y, Cell[] cells)
        {
            if (cells.Length > 0)
            {
                for (int i = 0; i < cells.Length; i++)
                {
                    Cell cell = cells[i];
                    if (cell != null && cell.trans)
                    {
                        Vector2 pos = cell.trans.anchoredPosition;
                        switch (main.alignment)
                        {
                            case Alignment.LeftTop:
                                if (i == 0)
                                {
                                    pos.x = x + cell.Width * 0.5f;
                                    pos.y = y - cell.Height * 0.5f;
                                }
                                else
                                {
                                    Cell preCell = cells[i - 1];
                                    pos.x = x + cell.Width * 0.5f;
                                    pos.y = preCell.trans.anchoredPosition.y - preCell.Height * 0.5f - main.space.y - cell.Height * 0.5f;
                                }
                                break;
                            case Alignment.RightTop:
                                if (i == 0)
                                {
                                    pos.x = x - cell.Width * 0.5f;
                                    pos.y = y - cell.Height * 0.5f;
                                }
                                else
                                {
                                    Cell preCell = cells[i - 1];
                                    pos.x = x - cell.Width * 0.5f;
                                    pos.y = preCell.trans.anchoredPosition.y - preCell.Height * 0.5f - main.space.y - cell.Height * 0.5f;
                                }
                                break;
                        }
                        cell.trans.anchoredPosition = pos;
                    }
                }
            }
        }

        public override void RefreshSize(Cell[] cells, ref float w, ref float h)
        {
            w = 0;
            for (int i = 0; i < cells.Length; i++)
            {
                Cell cell = cells[i];
                if (cell.trans)
                {
                    if (cell != null && cell.trans.gameObject.activeSelf && cell.Width > w)
                    {
                        w = cell.Width;
                    }
                }
            }
        }

        public override (float x, float y) GetInitPos()
        {
            float x = 0, y = 0;
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    if (main.endRow == null)
                    {
                        x = main.space.x;
                        y = -main.space.y;
                    }
                    else
                    {
                        x = main.endRow.x + main.endRow.width + main.space.x;
                        y = main.endRow.y;
                    }
                    break;
                case Alignment.RightTop:
                    if (main.endRow == null)
                    {
                        x = main.viewportSize.x - main.space.x;
                        y = -main.space.y;
                    }
                    else
                    {
                        x = main.endRow.x - main.endRow.width - main.space.x;
                        y = main.endRow.y;
                    }
                    break;
            }
            return (x, y);
        }

        public override bool HasFull()
        {
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    return main.endRow.x + main.endRow.width > main.viewportSize.x;
                case Alignment.RightTop:
                    return main.endRow.x - main.endRow.width < 0;
            }
            return false;
        }

        public override void SetRowPos(Row row)
        {
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    if (main.headRow == null)
                    {
                        row.x = main.viewportSize.x - main.space.x - row.width;
                    }
                    else
                    {
                        row.x = main.headRow.x - main.space.x - row.width;
                    }
                    break;
                case Alignment.RightTop:
                    if (main.headRow == null)
                    {
                        row.x = main.space.x + row.width;
                    }
                    else
                    {
                        row.x = main.headRow.x + main.space.x + row.width;
                    }
                    break;
            }
        }

        public override bool CanBreak()
        {
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    return main.headRow.x < main.space.x;
                case Alignment.RightTop:
                    return main.headRow.x > main.viewportSize.x - main.space.x;
            }
            return false;
        }

        public override bool SetXY(Row row, ref float x, ref float y)
        {
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    x += (row.width + main.space.x);
                    if (main.endRow.x + main.endRow.width > main.viewportSize.x)
                    {
                        return true;
                    }
                    break;
                case Alignment.RightTop:
                    x -= (row.width + main.space.x);
                    if (main.endRow.x - main.endRow.width < 0)
                    {
                        return true;
                    }
                    break;
            }
            return false;
        }

        public override bool IsCellsExceedsView()
        {
            float containerWidth = main.viewportSize.x - main.space.x;
            float contentWidth = 0;
            for (int i = 0; i < main.rows.Count; i++)
            {
                if (i > 0)
                {
                    contentWidth += main.space.x;
                }
                contentWidth += main.rows[i].width;
            }
            return contentWidth > containerWidth;
        }

        public override void ReduceSpeed()
        {
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    if (main.velocity > 0)
                    {
                        //右移
                        if (main.headRow.x > main.space.x)
                        {
                            main.velocityScale = (endActiveDis.x - (main.headRow.x - main.space.x)) / endActiveDis.x;
                            if (!main.hasTriggerHeadAction)
                            {
                                main._onScrollToHead?.Invoke();
                                main.hasTriggerHeadAction = true;
                            }
                        }
                        else
                        {
                            main.velocityScale = 1;
                        }
                    }
                    else if (main.velocity < 0)
                    {
                        //左移
                        if (main.cellsExceedsView)
                        {
                            //内容铺满超过视窗的情况，监听右端减速
                            if (main.endRow.x + main.endRow.width < main.viewportSize.x - main.space.x)
                            {
                                main.velocityScale = (endActiveDis.x - (main.viewportSize.x - (main.endRow.x + main.endRow.width) - main.space.x)) / endActiveDis.x;
                                if (!main.hasTriggerEndAction)
                                {
                                    main._onScrollToEnd?.Invoke();
                                    main.hasTriggerEndAction = true;
                                }
                            }
                            else
                            {
                                main.velocityScale = 1;
                            }
                        }
                        else
                        {
                            //全内容不能铺满视窗的情况，监听左端减速
                            if (main.headRow.x < main.space.x)
                            {
                                main.velocityScale = (main.headRow.x - (main.space.x - endActiveDis.x)) / endActiveDis.x;
                                if (!main.hasTriggerEndAction)
                                {
                                    main._onScrollToEnd?.Invoke();
                                    main.hasTriggerEndAction = true;
                                }
                            }
                            else
                            {
                                main.velocityScale = 1;
                            }
                        }
                    }
                    break;
                case Alignment.RightTop:
                    if (main.velocity > 0)
                    {
                        //右移
                        if (main.cellsExceedsView)
                        {
                            //内容铺满超过视窗的情况，监听左端减速
                            if (main.endRow.x - main.endRow.width > main.space.x)
                            {
                                main.velocityScale = (endActiveDis.x - (main.endRow.x - main.endRow.width - main.space.x)) / endActiveDis.x;
                                if (!main.hasTriggerEndAction)
                                {
                                    main._onScrollToEnd?.Invoke();
                                    main.hasTriggerEndAction = true;
                                }
                            }
                            else
                            {
                                main.velocityScale = 1;
                            }
                        }
                        else
                        {
                            //全内容不能铺满视窗的情况，监听右端减速
                            if (main.headRow.x > main.viewportSize.x - main.space.x)
                            {
                                main.velocityScale = (main.viewportSize.x - main.space.x + endActiveDis.x - main.headRow.x) / endActiveDis.x;
                                if (!main.hasTriggerEndAction)
                                {
                                    main._onScrollToEnd?.Invoke();
                                    main.hasTriggerEndAction = true;
                                }
                            }
                            else
                            {
                                main.velocityScale = 1;
                            }
                        }
                    }
                    else if (main.velocity < 0)
                    {
                        //左移
                        if (main.headRow.x < main.viewportSize.x - main.space.x)
                        {
                            main.velocityScale = (main.headRow.x - (main.viewportSize.x - main.space.x - endActiveDis.x)) / endActiveDis.x;
                            if (!main.hasTriggerHeadAction)
                            {
                                main._onScrollToHead?.Invoke();
                                main.hasTriggerHeadAction = true;
                            }
                        }
                        else
                        {
                            main.velocityScale = 1;
                        }
                    }
                    break;
            }
        }

        public override bool ElasticBack(float elastic)
        {
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    if (main.headRow.x - main.space.x > 1)
                    {
                        //左端从内部回弹
                        main.velocity = -(main.headRow.x - main.space.x - 0) * elastic;
                        return true;
                    }
                    if (main.cellsExceedsView)
                    {
                        //内容铺满超过视窗的情况，右端从内部回弹
                        if (main.endRow.x + main.endRow.width + main.space.x < main.viewportSize.x - 1)
                        {
                            main.velocity = (main.viewportSize.x - (main.endRow.x + main.endRow.width + main.space.x)) * elastic;
                            return true;
                        }
                    }
                    else
                    {
                        //内容不能铺满视窗的情况，左端从外部回弹
                        if (main.headRow.x - main.space.x < -1)
                        {
                            main.velocity = (0 - (main.headRow.x - main.space.x)) * elastic;
                            return true;
                        }
                    }
                    break;
                case Alignment.RightTop:
                    if (main.headRow.x + main.space.x < main.viewportSize.x - 1)
                    {
                        //右端从内部回弹
                        main.velocity = (main.viewportSize.x - (main.headRow.x + main.space.x)) * elastic;
                        return true;
                    }
                    if (main.cellsExceedsView)
                    {
                        //内容铺满超过视窗的情况，左端从内部回弹
                        if (main.endRow.x - main.endRow.width - main.space.x > 1)
                        {
                            main.velocity = -(main.endRow.x - main.endRow.width - main.space.x - 0) * elastic;
                            return true;
                        }
                    }
                    else
                    {
                        //内容不能铺满视窗的情况，右端从外部回弹
                        if (main.headRow.x + main.space.x > main.viewportSize.x + 1)
                        {
                            main.velocity = (main.viewportSize.x - main.space.x - main.headRow.x) * elastic;
                            return true;
                        }
                    }
                    break;
            }
            return false;
        }

        public override void MoveHeadRow()
        {
            main.headRow.x += main.velocity * main.velocityScale;
        }

        public override void MoveFollowHeadRow(Row row, Row preRow)
        {
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    row.x = preRow.x + preRow.width + main.space.x;
                    break;
                case Alignment.RightTop:
                    row.x = preRow.x - preRow.width - main.space.x;
                    break;
            }
        }

        public override void Reuse()
        {
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    if (main.velocity > 0)
                    {
                        //右移
                        if (main.endRow.x > main.viewportSize.x)
                        {
                            //右端
                            main.rows.RemoveAt(main.rows.Count - 1);
                            main.endRow.OnRecycle();
                            main.pool.Enqueue(main.endRow);
                            main.endRow = main.rows[main.rows.Count - 1];
                        }
                        if (main.headRow.x > 0)
                        {
                            //左端
                            int nextIndex = main.headRow.GetHeadCellIndex() - main.gridNum;
                            if (nextIndex >= 0)
                            {
                                float x = -99999;
                                float y = main.headRow.y;
                                Row newHeadRow;
                                if (main.pool.Count > 0)
                                {
                                    newHeadRow = main.pool.Dequeue();
                                    newHeadRow.OnReuse(x, y, ref nextIndex);
                                }
                                else
                                {
                                    newHeadRow = main._CreateNewRow(x, y, ref nextIndex);
                                }
                                newHeadRow.x = main.headRow.x - main.space.x - newHeadRow.width;
                                main.rows.Insert(0, newHeadRow);
                                main.headRow = newHeadRow;
                            }
                        }
                    }
                    else if (main.velocity < 0)
                    {
                        //左移
                        if (main.headRow.x + main.headRow.width < 0)
                        {
                            //左端
                            main.rows.RemoveAt(0);
                            main.headRow.OnRecycle();
                            main.pool.Enqueue(main.headRow);
                            main.headRow = main.rows[0];
                        }
                        if (main.endRow.x + main.endRow.width < main.viewportSize.x)
                        {
                            //右端
                            int nextIndex = main.endRow.GetEndCellIndex() + 1;
                            if (nextIndex > 1 && nextIndex < main.totalDataCount)
                            {
                                float x = main.endRow.x + main.endRow.width + main.space.x;
                                float y = main.endRow.y;
                                Row newEndRow;
                                if (main.pool.Count > 0)
                                {
                                    newEndRow = main.pool.Dequeue();
                                    newEndRow.OnReuse(x, y, ref nextIndex);
                                }
                                else
                                {
                                    newEndRow = main._CreateNewRow(x, y, ref nextIndex);
                                }
                                main.rows.Add(newEndRow);
                                main.endRow = newEndRow;
                            }
                        }
                    }
                    break;
                case Alignment.RightTop:
                    if (main.velocity > 0)
                    {
                        //右移
                        if (main.headRow.x - main.headRow.width > main.viewportSize.x)
                        {
                            //右端
                            main.rows.RemoveAt(0);
                            main.headRow.OnRecycle();
                            main.pool.Enqueue(main.headRow);
                            main.headRow = main.rows[0];
                        }
                        if (main.endRow.x - main.endRow.width > 0)
                        {
                            //左端
                            int nextIndex = main.endRow.GetEndCellIndex() + 1;
                            if (nextIndex > 1 && nextIndex < main.totalDataCount)
                            {
                                float x = main.endRow.x - main.endRow.width - main.space.x;
                                float y = main.endRow.y;
                                Row newEndRow;
                                if (main.pool.Count > 0)
                                {
                                    newEndRow = main.pool.Dequeue();
                                    newEndRow.OnReuse(x, y, ref nextIndex);
                                }
                                else
                                {
                                    newEndRow = main._CreateNewRow(x, y, ref nextIndex);
                                }
                                main.rows.Add(newEndRow);
                                main.endRow = newEndRow;
                            }
                        }
                    }
                    else if (main.velocity < 0)
                    {
                        //左移
                        if (main.endRow.x < 0)
                        {
                            //左端
                            main.rows.RemoveAt(main.rows.Count - 1);
                            main.endRow.OnRecycle();
                            main.pool.Enqueue(main.endRow);
                            main.endRow = main.rows[main.rows.Count - 1];
                        }
                        if (main.headRow.x < main.viewportSize.x)
                        {
                            //右端
                            int nextIndex = main.headRow.GetHeadCellIndex() - main.gridNum;
                            if (nextIndex >= 0)
                            {
                                float x = 99999;
                                float y = main.headRow.y;
                                Row newHeadRow;
                                if (main.pool.Count > 0)
                                {
                                    newHeadRow = main.pool.Dequeue();
                                    newHeadRow.OnReuse(x, y, ref nextIndex);
                                }
                                else
                                {
                                    newHeadRow = main._CreateNewRow(x, y, ref nextIndex);
                                }
                                newHeadRow.x = main.headRow.x + main.space.x + newHeadRow.width;
                                main.rows.Insert(0, newHeadRow);
                                main.headRow = newHeadRow;
                            }
                        }
                    }
                    break;
            }
        }

        public override float GetTouchPos(Vector2 uiPos)
        {
            return uiPos.x;
        }

        public override Vector2 EditModeUpdatePos(RectTransform child, int rowIndex, int gridIndex)
        {
            Vector2 pos = Vector2.zero;
            switch (main.alignment)
            {
                case Alignment.LeftTop:
                    pos.x = main.space.x + child.sizeDelta.x * 0.5f + (child.sizeDelta.x + main.space.x) * rowIndex;
                    break;
                case Alignment.RightTop:
                    pos.x = main.viewportSize.x - main.space.x - child.sizeDelta.x * 0.5f - (child.sizeDelta.x + main.space.x) * rowIndex;
                    break;
            }
            pos.y = -main.space.y - child.sizeDelta.y * 0.5f - (child.sizeDelta.y + main.space.y) * gridIndex;
            return pos;
        }
    }
}